/**
 * @file         bsc_can_device.h
 * @brief        CAN服务框架 ———— 设备对象
 * @note         组件内部使用，对接brd_can设备
 * @author       Jpz(puzhao.jin@hopechart.com, 靳普诏)
 * @data         2022-8-10
 * @version      1.0
 *
 * @par          修改日志
 * <table>
 * <tr><th>Date        <th>Version               <th>Author          <th>Description
 * <tr><td>2022-8-10   <td>1.0                   <td>Jpz             <td>创建初始版本
 * @copyright    杭州鸿泉物联网技术股份有限公司
 */
#ifndef _BSC_CAN_DEVICE_H_
#define _BSC_CAN_DEVICE_H_

#include "sfc/sfc_mutex.h"
#include "ofc/ofc_types.h"
#include "brd_can.h"


#ifdef __cplusplus
extern "C" {
#endif

// ~~~~~~~~~~~~~~~~~~~~ 常量定义 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// 设备对象属性ID
typedef enum TBsCanDeviceAttrIdTag TBsCanDeviceAttrId;
enum TBsCanDeviceAttrIdTag
{   
    kBsCanDeviceAttrIdBaud              = 0,    // 波特率，数据类型 Int32
    kBsCanDeviceAttrIdAutoRecover       = 1,    // 自动从Bus Off状态恢复，数据类型 Bool
    kBsCanDeviceAttrIdDetect            = 2,    // 自动侦测波特率模式，数据类型 Bool  
    kBsCanDeviceAttrIdPower             = 3,    // 电源类型（只写）， 数据类型 TBsCanPowerSupply
    kBsCanDeviceAttrIdRecvTick          = 4,    // 设备最近一次接收消息的tick值（只读），数据类型 UInt32

    kBsCanDeviceAttrIdChannel           = 10,   // 通道号（只读）， 数据类型 Int32

    kBsCanDeviceAttrIdEvtParams         = 11,   // 中断事件用户传（只写）， 参数据类型 void*
    kBsCanDeviceAttrIdEvtSentIsr        = 12,   // 发送事件中断函数指针（只写）， 数据类型 void*
    kBsCanDeviceAttrIdEvtRecvIsr        = 13,   // 接收事件中断函数指针（只写），数据类型 void*
    kBsCanDeviceAttrIdEvtBusOffIsr      = 14,   // Busoff事件中断函数指针（只写），数据类型 void*
    kBsCanDeviceAttrIdEvtDetectIsr      = 15,   // 自诊定事件中断函数指针（只写），数据类型 void*
    
};



// 每路状态
typedef struct TBsCanDeviceStatusEnumTag TBsCanDeviceStatusEnum;
struct TBsCanDeviceStatusEnumTag 
{
    UInt8 open      :1;    // 已打开
    UInt8 baudchange:1;    // baud调整中
    UInt8 buserror  :1;    // 总线错误
    UInt8 sent_isr  :1;     // 已发送
    UInt8 recv_isr  :1;    // 已接收
    UInt8 busoff_isr:1;    // busoff总线关闭
    UInt8 detect_isr:1;    // 波特率侦测事件
    UInt8 tx_disable:1;    // 设备禁止发送标志

};

typedef enum TBsCanDeviceStatusMaskTag TBsCanDeviceStatusMask;
enum TBsCanDeviceStatusMaskTag
{
    kBsCanDeviceStatusMaskNone  = 0,
    kBsCanDeviceStatusMaskOpen  = (0x01 << 0),  ///< 设备已打卡
    kBsCanDeviceStatusMaskBaud  = (0x01 << 1),  ///< (保留)
    kBsCanDeviceStatusMaskError = (0x01 << 2),  ///< (保留)
    kBsCanDeviceStatusMaskSent  = (0x01 << 3),  ///< 设备打开后发送过数据
    kBsCanDeviceStatusMaskRecv  = (0x01 << 4),  ///< 设备打开后接收过数据
    kBsCanDeviceStatusMaskBusOff  = (0x01 << 5),  ///< 设备处于bus off状态
    kBsCanDeviceStatusMaskDetectIsq  = (0x01 << 6),  ///< 设备处于波特率侦测状态
    kBsCanDeviceStatusMaskTxDisable  = (0x01 << 7),  ///< 设备处于禁止发送状态
 
};

typedef enum TBsBaudDetectStepTag TBsBaudDetectStep;
enum TBsBaudDetectStepTag
{
    kBsBaudDetectStep250K  = 0,
    kBsBaudDetectStep500K  = 1,
    kBsBaudDetectStep1000K = 2,
    kBsBaudDetectStep125K  = 3,
    kBsBaudDetectStep100   = 4,
};

typedef enum TBsCanDetectStateTag TBsCanDetectState;
enum TBsCanDetectStateTag
{
    kBsCanDetectStateNone       = 0x00,
    kBsCanDetectStateDealing    = 0x01,
    kBsCanDetectStateFail       = 0x02,
    kBsCanDetectStateSuccess    = 0x03,
};



// ~~~~~~~~~~~~~~~~~~~~~~~~ 重命名brd数据类型 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// 收发的CAN数据定义
typedef struct TCanDataTag TBsCanData;

// 
typedef enum TBsCanPowerSupplyTag TBsCanPowerSupply;
enum TBsCanPowerSupplyTag
{
    kBsCanPowerSupplyBase                    = 0,
    kBsCanPowerSupplyOn                      = kBsCanPowerSupplyBase,     ///< 设备电源开
    kBsCanPowerSupplyOff                     = 1,                        ///< 设备电源关
    kBsCanPowerSupplyMax,
};

typedef struct TBsCanDeviceTag TBsCanDevice;

/**
 * CAN数据发送后的事件,用于告知这个数据报是否发送成功
 * @param handle: 句柄
 * @param data_id: CAN数据id即为调用CAN发送时[TCanData.data_id](@ref TCanDataTag)
 * @param success: 用于表示数据是否发送成功,true表示发送成功,否则表示发送失败
 * @return 无返回值
 */
// typedef void (*Brd_TOnCanSent) (Brd_THandle handle, UInt32 data_id, Bool success);
typedef Brd_TOnCanSent TBsCanDeviceOnSent;
//typedef void (*TBsCanDeviceOnSent)(TBsCanDevice *sender, UInt32 data_id, Bool success);


/**
 * 收到CAN数据时的事件,主动发起通知，告知有收到数据
 * @param handle: 句柄
 * @return 无返回值
 */
// typedef void (*Brd_TOnCanRecv) (Brd_THandle handle);
typedef Brd_TOnCanRecv TBsCanDeviceOnRecv;
//typedef void (*TBsCanDeviceOnRecv)(TBsCanDevice *sender);


/**
 * CAN总线在Bus off时的触发的事件
 * @param handle: 句柄
 * @return 无返回值
 */
// typedef void (*Brd_TOnCanBusOff) (Brd_THandle handle);
typedef Brd_TOnCanBusOff TBsCanDeviceOnBusOff;
//typedef void (*TBsCanDeviceOnBusOff)(TBsCanDevice *sender);


/**
 * 波特率侦测事件,用于告知当前的波特率是否与总线匹配
 * @param handle: 句柄
 * @param success: 用于表示当前波特率与总线是否匹配,true表示匹配,否则表示不匹配
 * @return 无返回值
 */
// typedef void (*Brd_TOnCanDetect) (Brd_THandle handle, Bool success);
typedef Brd_TOnCanDetect TBsCanDeviceOnDetect;
//typedef void (*TBsCanDeviceOnDetect)(TBsCanDevice *sender, Bool success);

// ~~~~~~~~~~~~~~~~~~~~~ CAN设备对象 TBsCanDevice类 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// 设备对象
struct TBsCanDeviceTag
{
    Brd_THandle handler_;       ///< 底层CAN句柄
    TSfCriticalSection lock_;   ///< 临界区 多线程安全
    UInt32     recv_tick_;      ///< 最近一次成功接收数据的tick值
    UInt8      status;          ///< CAN状态位查询(@ref TBsCanDeviceStatus)
    UInt8      detect_status;   ///< 串口状态位标志 (@ref TBsCanDetectState)
    UInt8      detect_step;     ///< 自适应状态机(@ref TBsBaudDetectStep)
};

/**
 * 初始化设备对象
 * @param self          对象指针
 * @param channel       通道号
 * @param tx_frame        发送缓存地址
 * @param tx_frame_count   发送缓存大小
 * @param rx_frame        接收缓存地址
 * @param rx_frame_count   接收缓存大小
 * @return >= 0     成功
 *         <  0     失败
 */
Int32 TBsCanDeviceCreate(TBsCanDevice *self, UInt8 channel,
                        void *tx_frame, Int32 tx_frame_count, 
                        void *rx_frame, Int32 rx_frame_count);

/**
 * 析构设备对象                               
 * @param *self     对象指针
 * @return 
 */
void TBsCanDeviceDestroy(TBsCanDevice *self);

/**
 * 析构设备对象                               
 * @param   *self       对象指针
 * @param   *evt_obj    事件对象
 * @param   OnSent      发送事件                        
 * @param   OnRecv      接收事件
 * @param   OnBusOff    总线关闭事件
 * @param   OnDetect    自适应事件
 * @return  True    成功
 *          False   失败
 */
Bool TBsCanDeviceSetEvent(TBsCanDevice *self, void *evt_obj, 
                          TBsCanDeviceOnSent OnSent, 
                          TBsCanDeviceOnRecv OnRecv, 
                          TBsCanDeviceOnBusOff OnBusOff, 
                          TBsCanDeviceOnDetect OnDetect);                        
                        
/**
 * 设置属性
 * @param *self     对象指针
 * @param attr_id   TBsCanDeviceAttrId
 * @param *value    设定值地址 （指针类型不需要取地址，其他类型传入地址）
 * @param *ret_code 返回值（NULL时忽略返回值）
 * @return True     成功； False 失败
 */
Bool TBsCanDeviceSetAttr(TBsCanDevice *self, UInt32 attr_id, const void *value, Int32 *ret_code);

/**
 * 获取属性
 * @param *self         对象指针
 * @param attr_id       TBsCanDeviceAttrId
 * @param *ret_value    返回设定值地址 （指针类型不需要取地址，其他类型传入地址）
 * @param *ret_code     返回值（NULL时忽略返回值）
 * @return True     成功； False 失败
 */
Bool TBsCanDeviceGetAttr(TBsCanDevice *self, UInt32 attr_id, void *ret_value, Int32 *ret_code);

/**
 * 设置为自动侦测波特率模式或者正常收发模式
 * @param *self
 * @param detect    True: 自动侦测波特率模式; False: 正常收发模式
 * @return  >=  0   成功；
 *          <   0   失败；
 */
void TBsCanDeviceBaudDetect(TBsCanDevice *self, Bool detect);

/**
 * 打开设备
 * @param *self
 * @return >= 0     成功；
 *         <  0     失败；
 */
Int32 TBsCanDeviceOpen(TBsCanDevice *self);

/**
 * 关闭设备  
 * @param *self
 * @return >= 0     成功；
 *         <  0     失败；
 */
void TBsCanDeviceClose(TBsCanDevice *self);

/**
 * 检查是否打开  
 * @param *self
 * @return True     已打开；
 *         False    未打开；
 */
Bool TBsCanDeviceIsOpened(TBsCanDevice *self);

/**
 * 读取数据  
 * @param *self     对象指针
 * @param *can_data 数据地址
 * @param count     数据帧个数
 * @return  >=  0   成功，读取的个数；
 *          <   0   失败 
 */
Int32 TBsCanDeviceRead(TBsCanDevice *self, TCanData *can_data, Int32 count);

/**
 * 写入数据  
 * @param *self     对象指针
 * @param *can_data 数据地址
 * @param count     数据帧个数
 * @return  >=  0   成功，写入的个数；
 *          <   0   失败 
 */
Int32 TBsCanDeviceWrite(TBsCanDevice *self, const TCanData *can_data, Int32 count);
// 优先发送
Int32 TBsCanDeviceWritePreemptive(TBsCanDevice *self, const TCanData *can_data);

/**
 * 获取设备状态值 
 * @param *self     对象指针
 * @return  >=  0   成功 CAN状态位查询(@ref TBsCanDeviceStatus)
 *          <   0   失败 
 */
Int32 TBsCanDeviceStatus(TBsCanDevice *self);

/**
 * 用户手动清除设备状态位 
 * @note 设备打开位清除无效
 * @param *self     对象指针
 * @param status_mask 要清楚的状态位, 参考(@ref TBsCanDeviceStatusMask), 支持位与操作
 * @return 
 */
void TBsCanDeviceStatusClean(TBsCanDevice *self, UInt32 status_mask);



/**
 * 设置CAN模块处于Bus Off时,是否自动从Bus Off状态恢复
 * @note 
 *  -# 如果禁用自动恢复,则需要在BusOff后调用[TBsCanDeviceBusOffRecover()]来从BusOff状态恢复.
 *  -# 仅在CAN设备未打开前调用有效
 *  -# 如果禁用自动恢复,则必须设置[TBsCanDeviceOnBusOff](@ref kBsCanDeviceAttrIdEvtBusOffIsr)事件,否则设置无效
 * @param handle: 句柄
 * @param auto_recover: True: 自动从Bus Off状态恢复; False: 需手动恢复
 * @return 无返回值
 */
void TBsCanDeviceSetAutoRecover(TBsCanDevice *self, Bool auto_recover);

/**
 * 手动将Bus Off状态恢复到正常状态
 * @note 
     1.仅在Bus Off状态下调用
     2.Bus Off状态需要经过128个序列的,每个序列11个隐性位之后才能恢复.在这之前调用本函数,实际上跟自动恢复一样
 * @param handle: 句柄
 * @return 无返回值
 */
void TBsCanDeviceBusOffRecover(TBsCanDevice *self);

/**
 * 取消当前正在发送的CAN报文
 * @note 对于队列中data_id不为0的报文会产生[TBsCanDeviceOnSent](@ref kBsCanDeviceAttrIdEvtSentIsr)事件
 * @param handle: 句柄
 * @return 无返回值
 */
void TBsCanDeviceAbortSend(TBsCanDevice *self);

/**
 * 清除发送队列中的所有报文(包括优先发送的数据);
 * @note
 *  1. 仅在BusOff状态下调用有效
 *  2. 对于队列中data_id不为0的报文会产生[TBsCanDeviceOnSent](@ref kBsCanDeviceAttrIdEvtSentIsr)事件
 * @param handle: 句柄
 * @return 无返回值
 */
void TBsCanDeviceClearSendFifo(TBsCanDevice *self);

/**
 * 设置数据发送使能
 * @note 设备默认使能发送
 * @param *self
 * @param enable False:禁用发送,设备无法发送；True:使能发送,设备允许发送
 * @return 
 */
void TBsCanDeviceSetTxEnable(TBsCanDevice *self, Bool enable);

/**
 * 获取数据发送是否使能
 * @param *self
 * @return False:禁用发送,设备无法发送；True:使能发送,设备允许发送
 */
Bool  TBsCanDeviceTxEnable(TBsCanDevice *self);

/**
 * 获取错误帧个数
 * @param self 对象指针
 * @return 当返回值 >= 0 时, 表示实际获取的错误帧个数 \n
 *         当返回值 < 0 时, 表示失败, 参见[brd_common_def](@ref Brd_TErrorCodeTag)
 * @note 获取从open开始检测到的所有错误帧个数
 */
Int32 TBsCanDeviceGetErrorFrameCount(TBsCanDevice *self);

#ifdef __cplusplus
} // extern "C" {
#endif


#endif // #ifndef _BSC_CAN_DEVICE_H_

